From c486a04b282300bf2b0272a0c3d0512052f283e8 Mon Sep 17 00:00:00 2001 From: robertl Date: Wed, 4 Jun 2003 17:25:07 +0000 Subject: [PATCH] Initial checkin of magxfer. --- magxfer/Makefile | 6 + magxfer/magxfer | Bin 0 -> 18537 bytes magxfer/magxfer.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 565 insertions(+) create mode 100644 magxfer/Makefile create mode 100755 magxfer/magxfer create mode 100644 magxfer/magxfer.c diff --git a/magxfer/Makefile b/magxfer/Makefile new file mode 100644 index 000000000..6d0330fbe --- /dev/null +++ b/magxfer/Makefile @@ -0,0 +1,6 @@ +all: magxfer + +magxfer: magxfer.c + +clean: + rm -f magxfer diff --git a/magxfer/magxfer b/magxfer/magxfer new file mode 100755 index 0000000000000000000000000000000000000000..2a7d037f2767e5220b750c083718516ba3a4a309 GIT binary patch literal 18537 zcmeHvdwd+lm2S;+k2JPqNq&qU!ExHQgblGCmSt=U8~o5%Hpr5$EQ14>@o1){8CjYU zGd-3}kg->Q5sHHdZ1A$|F0U+E2#fh$LY{Y#!Lh?`c9)RkW^?1+HLR12Bjv7=Re}Nz zy5CpTJu`O9{bl!e|GTtQUG<$hb?VfqQ`Obg-E+6UVXMpK63*cknjo@{=-wK{x2;h* zHNp^iV!2o%K7m*W=G7bm55fr23?2j>K|`2eKpw+vq#2k;*_qmqClF385Q2f_MTwnn zApHdL5pF|)L&uKEdYSJ=)*R%|K_0`mff=Y5>tOJrjQ6naWiWsloV?1eXj^4hxV$SG zOZ8PG;}z8^52B@R^^LobQuVMd>NOK#A;Js<9tA3r=ec$oO`v-6@Zp?~K%G8@FdyLx zgbzD1HnAC`Es&TQb{1Ref_C*+Y*v`KX*aBW>=hF`N z0KaVK-vayy@H`ve4ZQbB-OIMm6m!K@h@V0J3>bj&-$Hm9xVlc^y}&1d8xS-96@>2t zzi(sOfRMS|t(!2djA>US$bE3i|4C2$z{8aw~Th@Hb=0{$AJpI#%9R>Djq;tA1hc87Wn zi0)ulS3D%*JytN$A%bo3ge8Jq!9=$RwI@w0n(Qν@)hEmKkAijs_W#DZO-Jz)mJ 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define xmalloc malloc +#define FRAME_SIZE 2000 + +int magfd; +struct termios orig_tio; +struct termios new_tio; + +int debug_level = 0; + +typedef struct { + unsigned int data_length; + unsigned char *data; +} vld; + +void dump_xframe(vld *frame); +void send_terminate(void); + +void +debug(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + if (0 == debug_level) + return; + + vfprintf(stderr, fmt, ap); +} + +/* + * Magellan uses a simple checksum of 16 bit words, but remember that + * things are optimized for the receiver, so they're big-endian. + */ +unsigned short +xor_checksum(unsigned char *p, int len) +{ + unsigned short data; + unsigned short checksum = 0; + int x; + + for (x = 0; x 0) { + if (debug_level >= 9) { + fprintf(stderr, ">%02x<", c); + } + return c; + } + } + fprintf(stderr, "Timeout. Unable to receive from GPS.\n"); + exit(1); +} + +/* + * Certain things in the protocol return a 3 byte sequence + * starting with '0x8e'. We know when these will happen, so + * we read until we get the 0x8e and intuit that the next two + * bytes are the numeric value to be returned. + */ +int get3(void) +{ + int x1,x2,x3; + while ((x1 = rxc()) != 0x8e) + ; + + x2 = rxc(); + x3 = rxc(); + + return (x2 << 8) | x3; +} + +/* + * Transmit a single framt to the unit. + */ +size_t +xmit_xframe(vld *frame, unsigned int frame_number) +{ + int i; + int acked_frame; + + if (debug_level > 3) { + dump_xframe(frame); + } + + if (debug_level > 0) { + fprintf(stderr, "Sending packet %d ", frame_number); + } + + if (frame->data_length == 6) { + int flen; + int unit_sum; + i = frame->data_length; + + write(magfd, frame->data, i); + + unit_sum = get3(); + if (unit_sum != 0) { + fprintf(stderr, "Final checksum was 0x%x instead of 0.\n", unit_sum); + exit(1); + } + + flen = get3() << 16; + flen |= get3(); + return flen; + } + + + /* + * First wait for unit to send us an OK, a hello, or an "I'm waiting" + */ +retry_tx: + for (i = 0; (i = rxc()) ;) { + if (i == 0x55) break; + if (i == 0x77) break; + if (i == 0xaa) break; + } + + i = frame->data_length + 10; + write(magfd, frame->data, i); + if (debug_level > 3) { + int x ; + fprintf(stderr, "Writing\n"); + for (x=0; x< i;x++) { + fprintf(stderr, "%02x ", frame->data[x]); + } + fprintf(stderr, "<\n"); + } + + /* + * Eat the 'OK' codes the unit spits out after the frame. + */ + for (i = 0; (i = rxc()) ;) { + if ((i != 0x55) && (i != 0xaa)) break; + } + + switch (i) { + case 0x77: + send_terminate(); + exit (1); + + case 0x81: + if (debug_level > 0) { + fprintf(stderr, "Retransmitting frame %d\n", + frame_number); + } + /* + * It's not documented, but the unit sends us two + * additional bytes in one of these. I'm guessing it's + * the checksum it computed. Read them and toss them. + */ + rxc(); + rxc(); + goto retry_tx; + + case 0x82: + fprintf(stderr, + "Unit saw rec length > 1024. We sent %d\n", + frame->data[0] << 8 | frame->data[1]); + exit(1); + default: + abort(); + case 0x8e: + break; + } + acked_frame = rxc() << 24; + acked_frame |= rxc() << 16; + + for (i = 0; (i = rxc()) ;) { + if ((i != 0x55) && (i != 0xaa)) break; + } + if (i == 0x77) send_terminate(); + + if (i != 0x8e) abort(); + acked_frame |= rxc() << 8; + acked_frame |= rxc(); + + /* + * The spec is actually wrong on this. It doesn't ack the frame + * we just sent. The ack contains the next frame it wants. + * This has been confirmed by Magellan Engineering. + */ + if (acked_frame != frame_number + 1) { + fprintf(stderr, "Got ack for %x. Expected %x\n", + acked_frame, frame_number); + abort(); + } + + if (debug_level > 0) { + fprintf(stderr, "Acked.\n"); + } + + return 0; +} + +/* + * Display a frame in human-readable format. + */ +void +dump_xframe(vld *frame) +{ + unsigned int i; + unsigned int edata = frame->data_length + 7; + unsigned int words; + unsigned int recnum; + unsigned int checksum; + + assert(frame->data[0] == '['); + debug("%x ", frame->data[0]); + + if (frame->data_length == 6) { + debug("TERMINATION FRAME: "); + for (i = 0; i < frame->data_length; i++) { + debug("%02x ", frame->data[i]); + } + return; + } + words = (frame->data[1] << 8) | frame->data[2]; + debug("Words: %04x ", words); + + recnum = (frame->data[3] << 24) | (frame->data[4] << 16) | + (frame->data[5] << 8) | (frame->data[6]); + + debug("Recnum: %08x\n", recnum); + + for (i = 0; i < frame->data_length; i++) { + debug("%02x ", frame->data[i+7]); + } + checksum = (frame->data[edata] << 8) | frame->data[edata+1]; + debug("Checksum: %04x ", checksum); +/* assert(0 == xor_checksum(&frame->data[3], frame->data_length + 4)); */ + assert(frame->data[edata+2] == ']'); + debug(" %x\n\n", frame->data[edata+2]); +} + +/* + * Prepare a packet for transmission by adding framing, checksum, etc. + */ +vld * +make_xframe(void *data, int len, int recno) +{ + vld *odata = xmalloc(sizeof *odata); + unsigned int words; + unsigned int aligned_len; + unsigned int checksum; + + /* + * Special case for termination. + */ + if (len == 0) { + odata->data = xmalloc(6); + odata->data[0] = '['; + odata->data[1] = 0; + odata->data[2] = 0; + odata->data[3] = 0; + odata->data[4] = 0; + odata->data[5] = ']'; + odata->data_length = 6; + return odata; + } + + /* Round to even word alignment */ + + aligned_len = (len + 1) & ~1; + words = (4 + aligned_len) / 2; + + odata->data = xmalloc(aligned_len + 9); + odata->data_length = aligned_len; + + odata->data[0] = '['; + + odata->data[1] = words >> 8; + odata->data[2] = words; + assert(words <= 1024); + + odata->data[3] = recno >> 24; + odata->data[4] = recno >> 16; + odata->data[5] = recno >> 8; + odata->data[6] = recno; + + /* If we had to insert padding, this ensures it's zero. If we + * didn't, it'll get clobbered by the memcpy which is fine. + */ + odata->data[aligned_len + 6] = 0; + memcpy(&odata->data[7], data, len); + + checksum = xor_checksum(&odata->data[3], aligned_len + 4); + odata->data[aligned_len + 7] = checksum >> 8; + odata->data[aligned_len + 8] = checksum; + odata->data[aligned_len + 9] = ']'; + + return odata; +} + +/* + * Something Very Bad has happened. Send a zero-length frame to the unit + * to tell it we're through playin' now. + */ +void +send_terminate(void) +{ + vld* vld; + + fprintf(stderr, "Hopelessly confused. Terminating upload.\n"); + + vld = make_xframe(NULL, 0, 0); + xmit_xframe(vld, 0); + exit(1); +} + + +/* + * Send 'sz' bytes from buf to the unit, chunking it up, framing it, and + * retransmitting chunks as needed. + */ +size_t +xmit(char *buf, int sz) +{ + int frame_number = 0; + int left = sz; + int n; + vld* vld; + + for (n = 0; n < sz - FRAME_SIZE; n += FRAME_SIZE,frame_number++) { + vld = make_xframe(&buf[n], FRAME_SIZE, frame_number); + xmit_xframe(vld, frame_number); + left -= FRAME_SIZE; + } + + if (left > 0) { + vld = make_xframe(&buf[n], left, frame_number); + xmit_xframe(vld, frame_number); + } + + vld = make_xframe(&buf[0], 0, frame_number++); + return xmit_xframe(vld, frame_number); +} + + +/* + * Given a numeric bitrate input, return a speed_t suitable for + * stuffing into a termios. + */ +speed_t +mkspeed(unsigned br) +{ + switch (br) { + case 1200: return B1200; + case 2400: return B2400; + case 4800: return B4800; + case 9600: return B9600; + case 19200: return B19200; +#if defined B57600 + case 57600: return B57600; +#endif +#if defined B115200 + case 115200: return B115200; +#endif + default: return B4800; + } +} + +void +restore_port() +{ + if (magfd) { + tcsetattr(magfd, TCSAFLUSH, &orig_tio); + } +} + +/* + * + */ +void +setup_port(const char *portname, unsigned bitrate) +{ + magfd = open (portname, O_RDWR); + + if (magfd < 0) { + fprintf(stderr, "Unable to open '%s'. Error: %s\n", + portname, strerror(errno)); + exit(1); + } + + tcgetattr(magfd, &orig_tio); + new_tio = orig_tio; + new_tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR| + IGNCR|ICRNL|IXON); + new_tio.c_oflag = 0; + new_tio.c_lflag = 0; + new_tio.c_cflag &= ~(CSIZE|PARENB); + new_tio.c_cflag |= CS8; + new_tio.c_cc[VTIME] = 10; + new_tio.c_cc[VMIN] = 0; + cfsetospeed(&new_tio, mkspeed(bitrate)); + cfsetispeed(&new_tio, mkspeed(bitrate)); + tcsetattr(magfd, TCSAFLUSH, &new_tio); +} + + +/* + * It might seem underambitious, but we really only need to send + * one command to the unit and we won't even get an ack back, so we + * just sort of spray it out there as a constant and hope to rendezvous + * soon. While the spec doesn't say it, we rendezvous at 115.2K, so we + * slam the local port to that speed immediately after we've written + * the data. + */ +void +send_upload_cmd(void) +{ +#define MU_CMD "$PMGNCMD,MPUPLOAD,2*72\r\n" +fprintf(stderr, "send_up %d\n", magfd); + write(magfd, MU_CMD, sizeof(MU_CMD)); + cfsetospeed(&new_tio, B115200); + cfsetispeed(&new_tio, B115200); + tcsetattr(magfd, TCSADRAIN, &new_tio); +} + +void +alarm_handler(int a) +{ + restore_port(); + fprintf(stderr, "Fatal error: No communications %d.\n", magfd); + exit(1); + +} + +/* + * Listen for "hello" packets from the unit. If found, the rendezvous must + * have succeeded so we send back a "hello". + */ +void +sync_receiver(void) +{ + int i; + int synced; + char c = 0x55; + + signal(SIGALRM, alarm_handler); + alarm(5); + + synced = 0; + for (i = 0;synced == 0;) { + switch (i = rxc()) { + case 0: break; + case 0xaa: synced=1; + case 0x77: synced=1; + } + } + + write(magfd, &c, 1); + + /* + * The spec says we shouldn't have to wait again, but this makes + * the communications setup way more reliable. + */ + synced = 0; + for (i = 0;synced == 0;) { + switch (i = rxc()) { + case 0: break; + case 0xaa: synced=1; + case 0x77: synced=1; + } + } +} + +int +main(int argc, char *argv[]) +{ + static char ibuf[10000000]; + unsigned short cksum; + size_t file_sz; + size_t sent_sz; + FILE *inf; + int c; + unsigned bitrate = 4800; + const char *portname = "/dev/ttyS0"; + const char *ifilename = "/dev/ttyS0"; + + while ((c = getopt(argc, argv, "f:p:b:D:")) != EOF) { + switch(c) { + case 'p': + portname = optarg; + break; + case 'f': + ifilename = optarg; + break; + case 'D': + debug_level = atoi(optarg); + break; + case 'b': + bitrate = atoi(optarg); + break; + default: + break; + } + } + setup_port(portname, bitrate); + send_upload_cmd(); + sync_receiver(); + + inf = fopen(ifilename, "r"); + file_sz = fread(ibuf, 1, sizeof(ibuf), inf); + + cksum = xor_checksum(ibuf, file_sz); + ibuf[file_sz++] = cksum >> 8; + ibuf[file_sz++] = cksum ; + + sent_sz = xmit(ibuf, file_sz); + if (sent_sz != file_sz) { + fprintf(stderr, "We sent %d bytes but the unit saw %d\n", + sent_sz, file_sz); + exit(1); + } + + return 0; +} -- 2.30.2